//
// Created by 张闳 on 2021/12/9.
// 基于libcurl重新封装一个http客户端
//

#ifndef MCOMMON_MHTTP_H
#define MCOMMON_MHTTP_H

#include <curl/curl.h>
#include "json.h"
#include "list.h"

#define HTTP_OK            200    /**< request completed ok */
#define HTTP_NOCONTENT        204    /**< request does not have content */
#define HTTP_MOVEPERM        301    /**< the uri moved permanently */
#define HTTP_MOVETEMP        302    /**< the uri moved temporarily */
#define HTTP_NOTMODIFIED    304    /**< page was not modified from last */
#define HTTP_BADREQUEST        400    /**< invalid http request was made */
#define HTTP_NOTFOUND        404    /**< could not find content for uri */
#define HTTP_BADMETHOD        405    /**< method not allowed for this uri */
#define HTTP_ENTITYTOOLARGE    413    /**<  */
#define HTTP_EXPECTATIONFAILED    417    /**< we can't handle this expectation */
#define HTTP_INTERNAL           500     /**< internal error */
#define HTTP_NOTIMPLEMENTED     501     /**< not implemented */
#define HTTP_SERVUNAVAIL    503    /**< the server is not available */


#define HTTP_CONTENT_TYPE_XFORM  "application/x-www-form-urlencoded;charset=UTF-8"
#define HTTP_CONTENT_TYPE_JSON "application/json;charset=UTF-8"
#define HTTP_CONTENT_TYPE_XML "application/xml;charset=UTF-8"

#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
#define IS_HEX_CHAR(ch)  (IS_UPPER_HEX(ch) || (ch >= 'a' && ch <= 'f'))

#define KEY_MAX_LENGTH 128
#define VALUE_MAX_LENGTH 1024

typedef enum {
    HTTP_GET,
    HTTP_POST,
    HTTP_PUT,
    HTTP_DELETE,
    HTTP_HEAD
} HTTP_REQUEST_TYPE;

/**
 * http请求结果对象
 */
struct http_response {
    char *response;
    size_t size;
};

/**
 * URL编码
 * @param src 源字符串
 * @param src_len 源字符串大小
 * @param dest 结果字符串
 * @param dest_len 结果串大小
 * @return
 */
char *urlencode(const char *src, const int src_len, char *dest, int *dest_len);

/**
 * URL解码
 * @param src   源字符串
 * @param src_len   源字符串大小
 * @param dest  结果字符串
 * @param dest_len  结果串大小
 * @return
 */
char *urldecode(const char *src, const int src_len, char *dest, int *dest_len);

char *urldecode_ex(const char *src, const int src_len, char *dest, int *dest_len);

/**
 * http kv链表，用于params,query和header
 */
typedef struct _http_key_value_pair {
    char key[KEY_MAX_LENGTH];
    size_t key_len;
    char value[VALUE_MAX_LENGTH];
    size_t value_len;
} http_key_value_pair_t;

typedef mlist_t http_key_value_pair_list;

/**
 * kv_put 向kv链表中插入数据
 * @param kv 链表指针
 * @param key
 * @param value
 */
void kv_put(void *kv, char *key, char *value);

/**
 * kv_get 从kv链表中提取key的值
 * @param kv
 * @param key
 * @return value
 */
char *kv_get(void *kv, char *key);


/**
 * kv_destory 销毁整个kv链表，释放内存空间
 * @param kv
 */
void kv_destory(void *kv);

/**
 * kv_popup 从kv链表中弹出第一个kv值
 * @param kv
 * @param key
 * @param value
 * @return
 */
//int kv_popup(http_key_value_pair_list *kv, char **key, char **value);

/**
 * 生成urlencode编码的参数串，可用于post的body与get的query串
 * @param params 参数kv键值对
 * @return
 */
char *http_build_params(void *params);

/**
 * 用url基础串加参数键值对生成完整GET模式的url地址
 * @param url
 * @param params
 * @return
 */
char *http_build_url_with_params(char *url, http_key_value_pair_list params);


/**
 * 基于libcurl的http get请求方法
 * @param url   URL地址
 * @param headers   特殊请求头，list<k,v>类型,用kv_put放入其中
 * @param params    请求参数，将自动组合到url中作为query部分，list<k,v>类型
 * @param response  返回请求结果对象指针，包含response与size两部分
 * @return  http_status 返回HTTP请求的状态码
 */
uint16_t http_get(const char *url, mlist_t headers, mlist_t params, struct http_response *response);

/**
 * 基于libcurl的http post form请求方法
 * @param url   URL地址
 * @param headers   特殊请求头，list<k,v>类型,用kv_put放入其中
 * @param params    请求参数，将自动组合到url中作为query部分，list<k,v>类型
 * @param response  返回请求结果对象指针，包含response与size两部分
 * @return  http_status 返回HTTP请求的状态码
 */
uint16_t http_post(const char *url, mlist_t headers, mlist_t params, struct http_response *response);

/**
 * 基于libcurl的http post json请求方法
 * @param url   URL地址
 * @param headers   特殊请求头，list<k,v>类型,用kv_put放入其中
 * @param json    请求参数json对象，json_doc对象指针类型
 * @param response  返回请求结果对象指针，包含response与size两部分
 * @return  http_status 返回HTTP请求的状态码
 */
uint16_t http_post_json(const char *url, mlist_t headers, json_doc *json, struct http_response *response);

/**
 * 基于libcurl的http post xml请求方法
 * @param url   URL地址
 * @param headers   特殊请求头，list<k,v>类型,用kv_put放入其中
 * @param xml    请求参数，xml字符串
 * @param response  返回请求结果对象指针，包含response与size两部分
 * @return  http_status 返回HTTP请求的状态码
 */
uint16_t http_post_xml(const char *url, mlist_t headers, const char *xml, struct http_response *response);


#endif //MCOMMON_MHTTP_H
